#include "QtGuiEx/RichTextEditorBar.qth"
#include "QtGuiEx/RichTextEditorBar.moh"
#include "QtGuiEx/ColorSelectorToolButton.qth"
#include <QtGui/QTextCharFormat>
#include <QtGui/QAction>
#include <QtGui/QFont>
#include <QtGui/QToolButton>
#include <QtGui/QFontComboBox>
#include <QtGui/QComboBox>
#include <QtGui/QMenu>
#include <cassert>

namespace QtGuiEx
{

RichTextEditorBar::RichTextEditorBar( QWidget* pParent)
	: QToolBar( pParent)
{
	this->setupCharFormattingActions();
	this->addSeparator();
	this->setupColorActions();
	this->addSeparator();
	this->setupFontActions();
	this->addSeparator();
	this->setupParagraphAlignmentActions();
	this->addSeparator();
	this->setupParagraphIndentActions();
	this->addSeparator();
	this->setupListActions();
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::setupCharFormattingActions()
{
	pBoldAction_ = new QAction( QIcon(":/RichTextEditor/Bold.png"), tr("Bold"), this);
	pBoldAction_->setShortcut( Qt::CTRL + Qt::Key_B);
	pBoldAction_->setCheckable( true);
	this->addAction( pBoldAction_);
	connect( pBoldAction_, SIGNAL( triggered()), this, SLOT( boldClicked()));


	pItalicAction_ = new QAction( QIcon(":/RichTextEditor/Italic.png"), tr( "Italic"), this);
	pItalicAction_->setShortcut( Qt::CTRL + Qt::Key_I);
	pItalicAction_->setCheckable( true);
	this->addAction( pItalicAction_);
	connect( pItalicAction_, SIGNAL( triggered()), this, SLOT( italicClicked()));


	pUnderlineAction_ = new QAction( QIcon(":/RichTextEditor/Underline.png"), tr( "Undeline"), this);
	pUnderlineAction_->setShortcut( Qt::CTRL + Qt::Key_U);
	pUnderlineAction_->setCheckable( true);
	this->addAction( pUnderlineAction_);
	connect( pUnderlineAction_, SIGNAL( triggered()), this, SLOT( underlineClicked()));

	pStrikeTroughAction_ = new QAction( tr("S"), this);
	pStrikeTroughAction_->setCheckable( true);
	this->addAction( pStrikeTroughAction_);
	connect( pStrikeTroughAction_, SIGNAL( triggered()), this, SLOT( strikeThroughClicked()));
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::setupColorActions()
{
	pTextColorSelectionButton_ = new ColorSelectorToolButton( Qt::black);
	pTextColorSelectionButton_->setIcon( QIcon(":/RichTextEditor/TextColor.png"));
	pTextColorSelectionButton_->setDefaultColor( Qt::black);
	this->addWidget( pTextColorSelectionButton_);
	connect( pTextColorSelectionButton_, SIGNAL( colorSelected( const QColor& )), this, SIGNAL( textColorSelected( const QColor& )));

	pBackgroundColorSelectionButton_ = new ColorSelectorToolButton( Qt::white);
	pBackgroundColorSelectionButton_->setIcon( QIcon(":/RichTextEditor/BackgroundColor.png"));
	pBackgroundColorSelectionButton_->setDefaultColor( Qt::white);
	this->addWidget( pBackgroundColorSelectionButton_);
	connect( pBackgroundColorSelectionButton_, SIGNAL( colorSelected( const QColor&)), this, SIGNAL( backgroundColorSelected( const QColor& )));
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::setupFontActions()
{
	pFontSelector_ = new QFontComboBox;
	this->addWidget( pFontSelector_);
	connect( pFontSelector_, SIGNAL(activated(const QString &)), this, SIGNAL(fontFamilySelected(const QString &)));

	pFontSizeSelector_ = new QComboBox;
	this->addWidget( pFontSizeSelector_);
	pFontSizeSelector_->setEditable( true);
	pFontSizeSelector_->addItem( "6");
	pFontSizeSelector_->addItem( "8");
	pFontSizeSelector_->addItem( "10");
	pFontSizeSelector_->addItem( "12");
	pFontSizeSelector_->addItem( "14");
	pFontSizeSelector_->addItem( "16");
	pFontSizeSelector_->addItem( "18");
	pFontSizeSelector_->addItem( "20");
	pFontSizeSelector_->addItem( "24");
	pFontSizeSelector_->addItem( "36");
	pFontSizeSelector_->addItem( "48");
	pFontSizeSelector_->addItem( "72");
	connect( pFontSizeSelector_, SIGNAL( activated( const QString&)), this, SLOT( fontSizeActivated( const QString&)));

}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::setupParagraphAlignmentActions()
{
	QActionGroup* pAlignGrp = new QActionGroup( this);

	pLeftAlignAction_ = new QAction( 
		QIcon( ":/RichTextEditor/LeftAlign.png"), tr( "Align paragraph to left"), this);
	pLeftAlignAction_->setCheckable( true);
	pAlignGrp->addAction( pLeftAlignAction_);

	pCenterAlignAction_ = new QAction( 
		QIcon( ":RichTextEditor/CenterAlign.png"), tr( "Align paragraph to center"), this);
	pCenterAlignAction_->setCheckable( true);
	pAlignGrp->addAction( pCenterAlignAction_);

	pRightAlignAction_ = new QAction( 
		QIcon( ":/RichTextEditor/RightAlign.png"), tr( "Align paragraph to right"), this);
	pRightAlignAction_->setCheckable( true);
	pAlignGrp->addAction( pRightAlignAction_);

	pJustifyAlignAction_ = new QAction( 
		QIcon( ":/RichTextEditor/JustifyAlign.png"), tr( "Justify paragraph"), this);
	pJustifyAlignAction_->setCheckable( true);
	pAlignGrp->addAction( pJustifyAlignAction_);

	this->addActions( pAlignGrp->actions());

	connect( pAlignGrp, SIGNAL( triggered( QAction*)), this, SLOT( textAlignClicked( QAction*)));
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::setupParagraphIndentActions()
{
	pIndentAction_ = new QAction( QIcon( ":/RichTextEditor/Indent.png"), tr( "Indent paragraph"), this);
	this->addAction( pIndentAction_);
	connect( pIndentAction_, SIGNAL( triggered()), this, SIGNAL( paragraphIndented()));

	pOutdentAction_ = new QAction( QIcon( ":/RichTextEditor/Outdent.png"), tr( "Outdent paragraph"), this);
	this->addAction( pOutdentAction_);
	connect( pOutdentAction_, SIGNAL( triggered()), this, SIGNAL( paragraphOutdented()));
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::setupListActions()
{
	pBulletListMenu_ = new QMenu();
	pCircleBulletAction_ = new QAction( QIcon( ":/RichTextEditor/CircleBullets.png"), tr("Circle bullet"), this);
	pBulletListMenu_->addAction( pCircleBulletAction_);
	pDiskBulletAction_ = new QAction( QIcon( ":/RichTextEditor/DiskBullets.png"), tr( "Disk bullet"), this);
	pBulletListMenu_->addAction( pDiskBulletAction_);
	pSquareBulletAction_ = new QAction( QIcon( ":/RichTextEditor/SquareBullets.png"), tr( "Square bullet"), this);
	pBulletListMenu_->addAction( pSquareBulletAction_);
	pBulletListMenu_->menuAction()->setCheckable(true);
	pBulletListMenu_->menuAction()->setIcon( QIcon( ":/RichTextEditor/DiskBullets.png"));
	this->addAction( pBulletListMenu_->menuAction());
	connect( pBulletListMenu_, SIGNAL( triggered( QAction*)), this, SLOT( bulletListStyleClicked( QAction*)));
	connect( pBulletListMenu_->menuAction(), SIGNAL( triggered()), this, SLOT( bulletListStyleClicked()));


	pNumberedListMenu_ = new QMenu();
	pDecimalListAction_ = new QAction( QIcon( ":/RichTextEditor/NumberedList.png"), tr( "Numbers"), this);
	pNumberedListMenu_->addAction( pDecimalListAction_);
	pLowerAlphaListAction_ = new QAction( QIcon( ":/RichTextEditor/LowerAlphaList.png"), tr("Lower alphabetic"), this);
	pNumberedListMenu_->addAction( pLowerAlphaListAction_);
	pUpperAlphaListAction_ = new QAction( QIcon( ":/RichTextEditor/UpperAlphaList.png"), tr( "Upper alphabetic"), this);
	pNumberedListMenu_->addAction( pUpperAlphaListAction_);
	pNumberedListMenu_->menuAction()->setCheckable( true);
	pNumberedListMenu_->menuAction()->setIcon( QIcon( ":/RichTextEditor/NumberedList.png"));
	this->addAction( pNumberedListMenu_->menuAction());
	connect( pNumberedListMenu_, SIGNAL( triggered( QAction*)), this, SLOT( numberedListStyleClicked( QAction*)));
	connect( pNumberedListMenu_->menuAction(), SIGNAL( triggered()), this, SLOT( numberedListStyleClicked()));

	listStyleToActionMap_[ QTextListFormat::ListCircle] = pCircleBulletAction_;
	listStyleToActionMap_[ QTextListFormat::ListDisc] = pDiskBulletAction_;
	listStyleToActionMap_[ QTextListFormat::ListSquare] = pSquareBulletAction_;
	listStyleToActionMap_[ QTextListFormat::ListDecimal] = pDecimalListAction_;
	listStyleToActionMap_[ QTextListFormat::ListLowerAlpha] = pLowerAlphaListAction_;
	listStyleToActionMap_[ QTextListFormat::ListUpperAlpha] = pUpperAlphaListAction_;

	actionToListStyleMap_[ pCircleBulletAction_] = QTextListFormat::ListCircle;
	actionToListStyleMap_[ pDiskBulletAction_] = QTextListFormat::ListDisc;
	actionToListStyleMap_[ pSquareBulletAction_] = QTextListFormat::ListSquare;
	actionToListStyleMap_[ pDecimalListAction_] = QTextListFormat::ListDecimal;
	actionToListStyleMap_[ pLowerAlphaListAction_] = QTextListFormat::ListLowerAlpha;
	actionToListStyleMap_[ pUpperAlphaListAction_] = QTextListFormat::ListUpperAlpha;
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::updateFromCharFormat( const QTextCharFormat& fmt)
{
	pBoldAction_->setChecked( fmt.font().bold());
	pItalicAction_->setChecked( fmt.font().italic());
	pUnderlineAction_->setChecked( fmt.font().underline());
	pStrikeTroughAction_->setChecked( fmt.font().strikeOut());

	pFontSelector_->setCurrentFont( fmt.font());
	QString sizeStr = QString::number( fmt.font().pointSize());
	pFontSizeSelector_->setEditText( sizeStr);
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::updateFromParagraphFormat( const QTextBlockFormat& blockFormat, const QTextListFormat& listFormat)
{
	Qt::Alignment alignment = blockFormat.alignment();
	if( alignment & Qt::AlignLeft)
	{
		pLeftAlignAction_->setChecked( true);
	}
	else if( alignment & Qt::AlignCenter)
	{
		pCenterAlignAction_->setChecked( true);
	}
	else if( alignment & Qt::AlignRight)
	{
		pRightAlignAction_->setChecked( true);
	}
	else if( alignment & Qt::AlignJustify)
	{
		pJustifyAlignAction_->setChecked( true);
	}

	if( QTextListFormat::ListStyleUndefined == listFormat.style())
	{
		pBulletListMenu_->menuAction()->setChecked( false);
		pNumberedListMenu_->menuAction()->setChecked( false);
	}
	else
	{
		QAction* pStyleAction = listStyleToActionMap_[ listFormat.style()];
		assert( NULL != pStyleAction);
		if( pStyleAction == pCircleBulletAction_ || pStyleAction == pDiskBulletAction_ || pStyleAction == pSquareBulletAction_)
		{
			pBulletListMenu_->menuAction()->setChecked( true);
			pNumberedListMenu_->menuAction()->setChecked( false);
		}
		else
		{
			pNumberedListMenu_->menuAction()->setChecked( true);
			pBulletListMenu_->menuAction()->setChecked( false);
		}
	}
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::boldClicked()
{
	Q_EMIT boldToggled( pBoldAction_->isChecked());
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::underlineClicked()
{
	Q_EMIT underlineToggled( pUnderlineAction_->isChecked());
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::italicClicked()
{
	Q_EMIT italicToggled( pItalicAction_->isChecked());
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::strikeThroughClicked()
{
	Q_EMIT strikeTroughToggled( pStrikeTroughAction_->isChecked());
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::fontSizeActivated( const QString& sizeStr)
{
	bool conversionSuccessful = false;
	float pointSize = sizeStr.toFloat( &conversionSuccessful);
	if( conversionSuccessful)
	{
		Q_EMIT fontSizeSelected( pointSize);
	}
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::textAlignClicked( QAction* pClickedAction)
{
	Qt::AlignmentFlag result = Qt::AlignHorizontal_Mask;
	if( pClickedAction == pLeftAlignAction_)
	{
		result = Qt::AlignLeft;
	} 
	else if( pClickedAction == pCenterAlignAction_)
	{
		result = Qt::AlignCenter;
	}
	else if( pClickedAction == pRightAlignAction_)
	{
		result = Qt::AlignRight;
	}
	else if( pClickedAction == pJustifyAlignAction_)
	{
		result = Qt::AlignJustify;
	}
	else
	{
		return;
	}
	Q_EMIT paragraphAlignSelected( result);
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::bulletListStyleClicked( QAction* pListAction)
{
	QTextListFormat::Style newStyle;
	if( NULL == pListAction)
	{
		if( pBulletListMenu_->menuAction()->isChecked())
		{
			newStyle = QTextListFormat::ListDisc;
			pNumberedListMenu_->menuAction()->setChecked( false);
		}
		else
		{
			newStyle = QTextListFormat::ListStyleUndefined;
		}
	}
	else
	{
		assert( actionToListStyleMap_.end() != actionToListStyleMap_.find( pListAction));
		pBulletListMenu_->menuAction()->setChecked( true);
		pNumberedListMenu_->menuAction()->setChecked( false);
		newStyle = actionToListStyleMap_[ pListAction];
	}
	Q_EMIT listStyleChanged( newStyle);
}

// ---------------------------------------------------------------------------------------------------------------------

void RichTextEditorBar::numberedListStyleClicked( QAction* pListAction)
{
	QTextListFormat::Style newStyle;
	if( NULL == pListAction)
	{
		if( pNumberedListMenu_->menuAction()->isChecked())
		{
			newStyle = QTextListFormat::ListDecimal;
			pBulletListMenu_->menuAction()->setChecked( false);
		}
		else
		{
			newStyle = QTextListFormat::ListStyleUndefined;
		}
	}
	else
	{
		assert( actionToListStyleMap_.end() != actionToListStyleMap_.find( pListAction));
		pNumberedListMenu_->menuAction()->setChecked( true);
		pBulletListMenu_->menuAction()->setChecked( false);
		newStyle = actionToListStyleMap_[ pListAction];
	}
	Q_EMIT listStyleChanged( newStyle);
}

} // namespace QtGuiEx